﻿using Autofac;
using Autofac.Builder;
using Autofac.Features.Scanning;
using Serilog;
using System;
using System.Collections.Generic;
using System.Reflection;
using YWM.DependencyInjection.Extensions;
using YWM.Localization;
using YWM.Session;

namespace YWM.DependencyInjection
{
    /// <summary>
    /// 容器创建器
    /// </summary>
    public class MyContainerBuilder
    {
        private readonly ContainerBuilder _containerBuilder;

        /// <summary>
        /// 依赖注入创建之前委托
        /// </summary>
        internal Action<ContainerBuilder> BeforeBuildAction;

        /// <summary>
        /// Serilog配置委托
        /// </summary>
        internal Action<LoggerConfiguration> LoggerConfigAction;

        internal MyContainerBuilder()
        {
            _containerBuilder = new ContainerBuilder();
        }

        /// <summary>
        /// 创建依赖注入
        /// </summary>
        /// <typeparam name="TStartupModule"></typeparam>
        /// <param name="isClientServer"></param>
        /// <returns></returns>
        internal IContainer Build<TStartupModule>(bool isClientServer) where TStartupModule : BaseModule
        {
            //设置并注册日志
            LoggerConfiguration loggerConfig = new LoggerConfiguration();
            LoggerConfigAction?.Invoke(loggerConfig);
            Log.Logger = loggerConfig.CreateLogger();
            RegisterInstance(Log.Logger);

            RegisterType<ISession, BaseSession>(isClientServer ? DependencyLifeTime.Singleton : DependencyLifeTime.Scoped);
            RegisterType<ILocalizationManager, LocalizationManager>();

            //注册模块
            TStartupModule startupModule = Activator.CreateInstance<TStartupModule>();
            List<(MethodInfo, object)> values = new List<(MethodInfo, object)>();
            CreateModules(startupModule, values);
            foreach ((MethodInfo methodInfo, object obj) in values)
            {
                methodInfo.Invoke(obj, null);
            }

            //依赖注入容器建立前的操作
            BeforeBuildAction?.Invoke(_containerBuilder);

            IContainer container = _containerBuilder.Build();
            return container;
        }

        /// <summary>
        /// 创建依赖注入模块
        /// </summary>
        /// <param name="containerBuilder"></param>
        /// <param name="startupModule"></param>
        private void CreateModules(object startupModule, List<(MethodInfo, object)> values)
        {
            Type moduleType = startupModule.GetType();
            DependsOnAttribute dependsOnAttribute = moduleType.GetCustomAttribute<DependsOnAttribute>();
            if (dependsOnAttribute != null && dependsOnAttribute.DependedModuleTypes != null && dependsOnAttribute.DependedModuleTypes.Length > 0)
            {
                foreach (Type type in dependsOnAttribute.DependedModuleTypes)
                {
                    object module = Activator.CreateInstance(type);
                    CreateModules(module, values);
                }
            }
            PropertyInfo propertyInfo = moduleType.GetProperty("ContainerBuilder", BindingFlags.NonPublic | BindingFlags.Instance);
            propertyInfo.SetValue(startupModule, this);
            MethodInfo methodInfo = moduleType.GetMethod(nameof(BaseModule.Initialize));
            methodInfo.Invoke(startupModule, null);
            methodInfo = moduleType.GetMethod(nameof(BaseModule.PostInitialize));
            values.Add((methodInfo, startupModule));
        }

        public void RegisterType<Type>(DependencyLifeTime dependencyLifeTime = DependencyLifeTime.Transient)
        {
            _containerBuilder.RegisterType<Type>().AsSelf().RegisterLifeTime(dependencyLifeTime);
        }

        public void RegisterType<ServiceType, ImplementationType>(DependencyLifeTime dependencyLifeTime = DependencyLifeTime.Transient)
        {
            _containerBuilder.RegisterType<ImplementationType>().As<ServiceType>().RegisterLifeTime(dependencyLifeTime);
        }

        public void RegisterType(Type type, DependencyLifeTime dependencyLifeTime = DependencyLifeTime.Transient)
        {
            _containerBuilder.RegisterType(type).AsSelf().RegisterLifeTime(dependencyLifeTime);
        }

        public void RegisterType(Type serviceType, Type implementationType, DependencyLifeTime dependencyLifeTime = DependencyLifeTime.Transient)
        {
            _containerBuilder.RegisterType(implementationType).As(serviceType).RegisterLifeTime(dependencyLifeTime);
        }

        public void RegisterInstance<T>(T instance) where T : class
        {
            _containerBuilder.RegisterInstance(instance);
        }

        public void RegisterGeneric(Type serviceType, Type implementationType, DependencyLifeTime dependencyLifeTime = DependencyLifeTime.Transient)
        {
            _containerBuilder.RegisterGeneric(implementationType).As(serviceType).RegisterLifeTime(dependencyLifeTime);
        }

        public void RegisterAssemblyType(Assembly assembly)
        {
            //每次解析都实例化一次
            _containerBuilder.RegisterAssemblyTypes(assembly)
                .Where(t => typeof(ITransient).IsAssignableFrom(t) && t != typeof(ITransient))
                .AsImplementedInterfaces()
                .AsSelf()
                .InstancePerDependency();
            //在嵌套方法中仅实例化一次
            _containerBuilder.RegisterAssemblyTypes(assembly)
               .Where(t => typeof(IScoped).IsAssignableFrom(t) && t != typeof(IScoped))
               .AsImplementedInterfaces()
               .AsSelf()
               .InstancePerLifetimeScope();
            //应用程序运行中仅实例化一次
            _containerBuilder.RegisterAssemblyTypes(assembly)
               .Where(t => typeof(ISingleton).IsAssignableFrom(t) && t != typeof(ISingleton))
               .AsImplementedInterfaces()
               .AsSelf()
               .SingleInstance();
        }

        public IRegistrationBuilder<object, ScanningActivatorData, DynamicRegistrationStyle> RegisterAssemblyTypes(params Assembly[] assemblies)
        {
            return _containerBuilder.RegisterAssemblyTypes(assemblies);
        }
    }
}
